home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / telecomm / bbs / axshsupp.lha / AXsh-Last.lha / usr / src / utils / last.c
C/C++ Source or Header  |  1993-01-08  |  5KB  |  220 lines

  1. /*
  2.  * Purpose
  3.  * -------
  4.  *   Last-command for AXsh.  Searches through a file containing
  5.  * info on user login times, and prints specific information.  See
  6.  * last.man for further info.
  7.  *
  8.  * Technique
  9.  * ---------
  10.  *   The applied technique is to search the file from start to
  11.  * end and store matching lines in a circular double-linked list.
  12.  * If the output limiter <-N> is used, no more memory than for N
  13.  * lines will be allocated, and the oldest ones will be recycled.
  14.  * In this way both disk access and memory usage is kept relatively
  15.  * low.
  16.  *
  17.  *   Dynamic allocation is used for obtaining space for the lines,
  18.  * and if the program terminates normally, it frees the memory
  19.  * itself.  If the user presses CTRL-C, the compiler's own routine
  20.  * handles the cleanup, including closing of files and deallocation
  21.  * of memory, even the dynamic allocated areas.  I'm not sure if
  22.  * all compilers do this (correctly), but SAS/C 6.1 seems to handle
  23.  * it fine.
  24.  *
  25.  *   The program only allocates 40 characters for each line, as the
  26.  * lines in the file are usually 37 or 38 characters long (including
  27.  * the carriage return).  However this can be increased easily by
  28.  * changing the value of LINE_LEN.
  29.  *
  30.  * Syntax
  31.  * ------
  32.  *   "last [-N] [login name]"
  33.  *
  34.  *   <-N> limits output to N lines.
  35.  *
  36.  *   <login name> is the login of the user to search for and
  37.  * defaults to anybody.
  38.  *
  39.  *
  40.  * History
  41.  * -------
  42.  *   02-Oct-92  Mads Haahr      First version completed.
  43.  *   08-Jan-93  Mads Haahr      Now supports varying line lengths (thanks
  44.  *                              Pasi), general program structure changed,
  45.  *                              most of the code rewritten.
  46.  *
  47.  */
  48.  
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <stdarg.h>
  52. #include <string.h>
  53.  
  54. #define LAST_FILE   "AXsh:etc/Last" /* Name of the last file.             */
  55. #define LINE_LEN    40              /* Max length of a line minus one.    */
  56.  
  57. /* Structures.
  58.  */
  59. struct line
  60. {
  61.     char value[LINE_LEN];
  62.     struct line *next, *prev;
  63. };
  64.  
  65. /* Prototypes.
  66.  */
  67. void store(char *s),
  68.      cleanup(void),
  69.      error(char *s, ...);
  70.  
  71. /* Global variables.
  72.  */
  73. FILE *fp;
  74. int lines = 0, count = 0;
  75. struct line *first = NULL, *last = NULL;
  76.  
  77. int main(int argc, char *argv[])
  78. {
  79.     struct line *tmp;
  80.     char buf[LINE_LEN], match[LINE_LEN] = "\0";
  81.     int i;
  82.  
  83.     switch(argc)
  84.     {
  85.         case 1 :
  86.             break;
  87.  
  88.         case 2 :
  89.             if (argv[1][0] == '-')
  90.             {
  91.                 lines = -atoi(argv[1]);
  92.                 if (lines <= 0) error("Illegal number of lines", 0);
  93.             }
  94.             else
  95.                 strncpy(match, argv[1], LINE_LEN-1);
  96.             break;
  97.  
  98.         case 3 :
  99.             if (argv[1][0] == '-')
  100.             {
  101.                 lines = -atoi(argv[1]);
  102.                 if (lines <= 0) error("Illegal number of lines", 0);
  103.             }
  104.             else
  105.                 error("Second argument is incorrect", 0);
  106.             strncpy(match, argv[2], LINE_LEN-1);
  107.             break;
  108.  
  109.         default :
  110.             error("Too many arguments", 0);
  111.  
  112.     }
  113.  
  114.     /* Open the last file.
  115.      */
  116.     if ((fp = fopen(LAST_FILE, "r")) == NULL) error("Could not open ", LAST_FILE, 0);
  117.  
  118.     /* Here begins the actual
  119.      * reading & matching.
  120.      */
  121.     while (fgets(buf, LINE_LEN, fp) != NULL)
  122.         if (strstr(buf, match))
  123.             store(buf);
  124.  
  125.     /* Now we print out what we've found.
  126.      */
  127.     for(tmp=last,i=count; i--; tmp=tmp->prev) printf("%s", tmp->value);
  128.  
  129.     cleanup();
  130.  
  131.     return(0);
  132. }
  133.  
  134.  
  135. void store(char *s)
  136. {
  137.     struct line *tmp;
  138.  
  139.     /* First check if no structures
  140.      * have been allocated yet.
  141.      */
  142.     if (first == NULL)
  143.     {
  144.         /* Allocate memory for first
  145.          * structure and initialize it.
  146.          */
  147.         if ((first = malloc(sizeof(struct line))) == NULL) error("Memory allocation failed", 0);
  148.         first->next = first;
  149.         first->prev = first;
  150.         last = first;
  151.  
  152.         /* Store the string and set
  153.          * the line counter.
  154.          */
  155.         strncpy(first->value, s, LINE_LEN);
  156.         count = 1;
  157.  
  158.         return;
  159.     }
  160.  
  161.     if (count < lines || lines == 0)
  162.     {
  163.         /* We haven't reached max the number of lines
  164.          * yet, so we allocate memory for one more.
  165.          */
  166.         if ((tmp = malloc(sizeof(struct line))) == NULL)
  167.             error("Memory allocation failed", 0);
  168.  
  169.         /* Link the new structure in
  170.          * and update the <last> pointer.
  171.          */
  172.         tmp->prev = last;
  173.         last->next = tmp;
  174.         tmp->next = first;
  175.         first->prev = tmp;
  176.         last = tmp;
  177.  
  178.         /* Store the string and increment
  179.          * the line counter.
  180.          */
  181.         strncpy(tmp->value, s, LINE_LEN);
  182.         count++;
  183.     }
  184.     else
  185.     {
  186.         /* We have reached the max number of
  187.          * lines, so we recycle the oldest one.
  188.          */
  189.         strncpy(first->value, s, LINE_LEN);
  190.         last = first;
  191.         first = first->next;
  192.     }
  193. }
  194.  
  195.  
  196. void cleanup(void)
  197. {
  198.     struct line *tmp;
  199.  
  200.     if (fp) fclose(fp);
  201.  
  202.     for(tmp=first; count--; tmp=tmp->next) free(tmp);
  203. }
  204.  
  205.  
  206. void error(char *s, ...)
  207. {
  208.     va_list ap;
  209.  
  210.     printf("Last: ");
  211.     for(va_start(ap, s);s;s=va_arg(ap, char *)) printf("%s", s);
  212.     printf(".\n");
  213.     va_end(ap);
  214.  
  215.     cleanup();
  216.  
  217.     exit(10);
  218. }
  219.  
  220.